﻿using System;
using System.Xml;
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;

using Weazel.Gezel.Model;

namespace Weazel.Gezel.Exporter
{
	internal class IpBlockExporter
	{
    /// <summary>
    /// Convert a gezel ipblock to
    /// its xml representation.
    /// </summary>
    /// <param name="xmlDoc">recieves output</param>
    /// <param name="parent">parent xml element</param>
    /// <param name="ipBlock">ipblock to convert</param>
		internal static void ToXml(XmlDocument xmlDoc, XmlElement parent, IPBlock ipBlock)
		{
      XmlElement ipblockElement = xmlDoc.CreateElement("IpBlock");
      ipblockElement.SetAttribute("iptype", ipBlock.IpType);

      foreach (string parameter in ipBlock.IpParameters)
      {
        XmlElement parameterElement = xmlDoc.CreateElement("Parameter");
        parameterElement.InnerText = parameter;
        ipblockElement.AppendChild(parameterElement);
      }

      if (ipBlock.InPorts.Count > 0)
      {
        XmlComment inportsComments = xmlDoc.CreateComment("inports");
        ipblockElement.AppendChild(inportsComments);

        foreach (InPort inport in ipBlock.InPorts.Values)
        {
          PortExporter.ToXml(xmlDoc, ipblockElement, inport);
        }
      }

      if (ipBlock.OutPorts.Count > 0)
      {
        XmlComment outportsComment = xmlDoc.CreateComment("outports");
        ipblockElement.AppendChild(outportsComment);

        foreach (OutPort outport in ipBlock.OutPorts.Values)
        {
          PortExporter.ToXml(xmlDoc, ipblockElement, outport);
        }
      }

      parent.AppendChild(ipblockElement);
		}

		internal static void ToGezel(System.CodeDom.Compiler.IndentedTextWriter textWriter, Weazel.Gezel.Model.IPBlock ipBlock)
		{
			string portsString;
			if (ipBlock.InPorts.Count > 0 || ipBlock.OutPorts.Count > 0)
			{
				// sort ports to ensure that they are output 
				// in the their original order since
				// gezel (unfortunately) uses positional 
				// port binding instead of named binding
				List<Port> ports = new List<Port>(ipBlock.InPorts.Count + ipBlock.OutPorts.Count);
				foreach (Port port in ipBlock.InPorts.Values)
					ports.Add(port);
				foreach (Port port in ipBlock.OutPorts.Values)
					ports.Add(port);
				ports.Sort();

				StringBuilder buffer = new StringBuilder("(\n");
				foreach (Port port in ports)
				{
					buffer.AppendFormat(
						"    {0} {1} : {2}({3});\n",
						port is InPort ? "in" : "out",
						port.LocalName,
						port.Signed ? "tc" : "ns",
						port.Width
					);
				}

				// remove last semi-colon
				buffer.Remove(buffer.Length - 2, 1);
				buffer.Append(")");
				portsString = buffer.ToString();
			}
			else
			{
				portsString = string.Empty;
			}


			textWriter.WriteLine("ipblock {0} {1}", ipBlock.LocalName, portsString);
			textWriter.WriteLine("{");
			textWriter.Indent++;

			textWriter.WriteLine("iptype \"{0}\";", ipBlock.IpType);

			foreach (string ipparameter in ipBlock.IpParameters)
			{
				textWriter.WriteLine("ipparm \"{0}\";", ipparameter);
			}

			textWriter.Indent--;
			textWriter.WriteLine("}");
			textWriter.WriteLine();
		}
	}
}
